iT邦幫忙

2023 iThome 鐵人賽

DAY 16
0
Modern Web

給前端新手的圖文故事系列 第 16

初步了解物件陣列與物件(Arrays and Objects)

  • 分享至 

  • xImage
  •  

資料結構操作應用

這邊先講一下什麼是資料結構,資料結構(Data Structure)是電腦儲存並組織資料的方式,簡單的來說,就是當資料處存在記憶體中時,決定資料的存放位子以及順序的,就是所謂的資料結構。

在這裡先把話題拉回來,實際上在 JavaScript 當中,我們的任何東西其實都是物件,雖然這並不意味著我們無法操作資料結構,但在此我們還是會先以物件的操作為主,並且實際上資料結構是門很深的學科,常見的資料結構就有陣列(Array)、堆疊(Stack)、樹狀結構(Tree)等等,因此若我們所學習的目標並非演算法的話,那這道大題我們可以先跳過不做。

物件的操作

物件操作是 JavaScript 的根基,基本上 JavaScript 的一切始於物件並終於物件,雖然這樣說有些玄學,但實際上其實並沒有這麼複雜,就跟 DOM 以及全部的變數宣告與函式呼叫一樣,他在語法上並非難以操作,也一般物件的使用也是如此。

宣告物件

在語法的操作上,設計一個物件並不困難,我們僅需要藉由一個 {} 即可完成宣告,並且在建立物件的階段,我們也可以決定是否放置內容值,而即使在此數不放置內容,後續的內容擴充新增也並不困難。

宣告一個新物件

在物件宣告中,我們可以藉由 new Object() 這個函式建立物件,但這樣做除了讓字數變多外,其實並沒有任何顯著的特點,因此大多數情況我們會避免此操作。

操作方式

const person = new Object();

實際範例

以下的範例是物件最常使用的宣告形式,並且在賦予值的過程也非常簡單

const person = {};

console.log(person);
// 輸出:{}
const person = { name: 'Alex', age: 25 };

console.log(person);
// 輸出:{name: 'Alex', age: 25}

這此處有一個概念,理論上 key 跟 value 是程度出現的,在操作上不會出現有 key 但沒有 value 的情況,而若目前真的沒有值得話,可以先填入如 null 等純值。

object = {name1: value1, name2: value2, ...}

操作物件

在物件的操作上,我們最常用的方式其實就是訪問該物件的某個特定內容(key),舉例來說,一個人可以被命名,同時他的名字也可以被拿到各種地方使用,而操作 key 內容的這個方式,可以很輕鬆的藉由一個 dot notation (.) 完成。

操作方式

我們這邊可以藉由物件後面接一個 . ,就可以去取得他 key 的內容,並且在使用指定運算式的情況下,還可以將 key 進行賦值操作

objectName.propertyName

實際範例

const person = {};
person.name = 'Alex'
person.age = 25

console.log(person);
// 輸出:{name: 'Alex', age: 25}

console.log(person.name);
// 輸出:Alex

取得 Object 的值

其實在通常的情況下,我們使用 . 就可以幫我們去取得 Object 的值,但有時我們可能會需要全部的內容,因此 Object 也提供了相應的操作,並且會幫我們將內容存成陣列

操作方式

Object.values()

實際範例

const person = { name: 'Alex', age: 25 };

console.log(Object.values(person));
// 輸出:['Alex', 25]

// 這裡也可以藉由[]的方式輸入內容,內容將匹配到對應字串的 key 中
console.log(person['name'])
// 輸出: Alex

取得 Object 的 key

操作方式

Object.keys()

實際範例

const person = { name: 'Alex', age: 25 };

console.log(Object.keys(person));
// 輸出:['name', 'age']

刪除 Object 上的項目

操作方式

delete obj.key1

實際範例

const person = { name: 'Alex', age: 25 };
delete person.name;

console.log(person);
// 輸出:{age: 25}

object 轉成 array of array

const person = { name: 'Alex', age: 25 };

console.log(Object.entries(person));
// (2) [Array(2), Array(2)]
// 0: (2) ['name', 'Alex']
// 1: (2) ['age', 25]
// length: 2

array of array 轉回 Object

const person = [
  ['name', 'Alex'],
  ['age', 25],
];

console.log(Object.fromEntries(person));
// 輸出:{name: 'Alex', age: 25}

實際範例

線上 3D 圖書顯示產生器

<a class="book-container" href="#" target="_blank">
    <div class="book">
      <img alt="" src="" />
   </div>
</a>
.book-container {
  display: flex;
  align-items: center;
  justify-content: center;
  perspective: 600px;
}

@keyframes initAnimation {
  0% {
    transform: rotateY(0deg);
  }
  100% {
    transform: rotateY(-11deg);
  }
}

.book {
  width: 300px;
  height: 300px;
  position: relative;
  transform-style: preserve-3d;
  transform: rotateY(-11deg);
  transition: 1s ease;
  animation: 1s ease 0s 1 initAnimation;
}

.book:hover {
  transform: rotateY(0deg);
}

.book > :first-child {
  position: absolute;
  top: 0;
  left: 0;
  background-color: red;
  width: 300px;
  height: 300px;
  transform: translateZ(25px);
  background-color: #01060f;
  border-radius: 0 2px 2px 0;
  box-shadow: 5px 5px 20px #666;
}

.book::before {
  position: absolute;
  content: ' ';
  background-color: blue;
  left: 0;
  top: 3px;
  width: 48px;
  height: 294px;
  transform: translateX(172px) rotateY(90deg);
  background: linear-gradient(
    90deg,
    #fff 0%,
    #f9f9f9 5%,
    #fff 10%,
    #f9f9f9 15%,
    #fff 20%,
    #f9f9f9 25%,
    #fff 30%,
    #f9f9f9 35%,
    #fff 40%,
    #f9f9f9 45%,
    #fff 50%,
    #f9f9f9 55%,
    #fff 60%,
    #f9f9f9 65%,
    #fff 70%,
    #f9f9f9 75%,
    #fff 80%,
    #f9f9f9 85%,
    #fff 90%,
    #f9f9f9 95%,
    #fff 100%
  );
}

.book::after {
  position: absolute;
  top: 0;
  left: 0;
  content: ' ';
  width: 300px;
  height: 300px;
  transform: translateZ(-25px);
  background-color: #01060f;
  border-radius: 0 2px 2px 0;
  box-shadow: -10px 0 50px 10px #666;
}
const book = document.querySelector('.book-container');

const gameObject = {
  name: 'Spirit Island',
  chineseName: '精靈島 / 靈跡島',
  type: '合作遊戲',
  weight: 4.04,
  rating: 8.4,
  bggUrl: 'https://boardgamegeek.com/boardgame/162886/spirit-island',
  coverUrl:
    'https://cf.geekdo-images.com/a13ieMPP2s0KEaKNYmtH5w__itemrep/img/OxbJV22OSI7wvhs0MFn1rF4tHz4=/fit-in/246x300/filters:strip_icc()/pic3615739.png',
  author: {
    name: 'R. Eric Reuss',
    age: 33,
    email: 'test@foo.com',
    directions:
      'Eric Reuss is a board game designer living in the greater Boston area',
  },
  aboutGame: function () {
    return `這個遊戲叫${this.name}`;
  },
};

console.log(gameObject);
// 輸出:整個物件
console.log(gameObject.name);
// 輸出:Spirit Island
console.log(gameObject.aboutGame());
// 輸出:這個遊戲叫Spirit Island

// 修改這個 HTML 本身的 href 屬性(這邊因為剛好是 a tag 所以方便直接操作)
book.href = gameObject.bggUrl;
// 修改書本裡的 img 的 src 屬性
book.querySelector('img').src = gameObject.coverUrl;
// 修改書本裡的 img 的 alt 屬性
book.querySelector('img').alt = gameObject.name;

這邊其實同學應該會發現,我們大多數的資料是沒有做使用的,而在實際專案上這其實是蠻常發生的事情,而大多數時候我們其實也很難去預期需求的擴充,因此偶爾多準備一些資料其實沒有什麼大礙(但以資料傳輸的區塊來看,多傳的資料確實是浪費的)

陣列基礎操作

其實在 JavaScript 中陣列也是物件,但實際上的差異這裡可以先忽略不談,跟大多數程式語言一樣,陣列的 index 計算都是由 0 開始,並且所以值雷同於我們在 object 中的 key,也可以理解為我們訪問或操作陣列時的鑰匙。

零號房間住的是可頌、一號房間住的是三明治、二號房間是甜甜圈,最後的三號房間是不同的甜甜圈

額外提及一個概念,在網頁開發中我的的複數資料幾乎都是藉由 array 進行儲存,因此學習好 array 的操作是一件非常重要的事情。

Array 的所有操作方式

宣告陣列

在語法的操作上,設計一個陣列並不困難,我們僅需要藉由一個 [] 即可完成宣告,但在與建立物件時的不同, new Array() 實際上有一些額外的操作在下方會提及,因此 new Array()並不會完全不見蹤影。

宣告一個新陣列

我們可以藉由 new Array() 這個函式建立陣列,但跟物件的宣告一樣,我們在宣告時往往喜歡使用更簡單的方式來進行操作。

const fruits = new Array();

圖示範例

較常見的宣告方式

const fruits = [];

console.log(fruits);
// 輸出:[]
const fruits = ['apple', 'banana', 'orange'];

console.log(fruits);
// 輸出: ['apple', 'banana', 'orange']

除此之外其實陣列有一些比較有趣的操作方式

const fruits = new Array(5);

console.log(fruits);
// 輸出:[空白*5] 五個空值的陣列,長度為 5

// 如果是輸入非單一數字的話將會建立內容
const arrayDemo = new Array(1, 2, 3);

console.log(arrayDemo);
// 輸出:[1, 2, 3]

多維陣列概念

const array = [
  [1, 2, 3, 4],
  [1, 2, 3, 4],
  [1, 2, 3, 4],
];

console.log(array);
// 輸出: [Array(4), Array(4), Array(4)]

填滿陣列內容 fill

操作方式

array.fill(value, start, end)

圖示範例

實際範例

let fruits = new Array(5);

console.log(fruits);
// 輸出:[]

// 將房間內填滿輸入的內容
fruits.fill('');

console.log(fruits);
// 輸出:['', '', '', '', '']

fruits = fruits.map((_e, index) => index + 1);

// fruits = fruits.map(function (e, index) {
//   return index + 1;
// });

console.log(fruits);
// 輸出:[1, 2, 3, 4, 5]
const test = [];
for (let index = 1; index <= 10; index++) {
  test.push(index);
}
console.log(test);
// 輸出:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let fruits = new Array(8).fill('').map((e, index) => (e = index * 2));

console.log(fruits);
// 輸出:[0, 2, 4, 6, 8, 10, 12, 14]

確認陣列的長度 length

在陣列的操作中,我們很常去取得陣列的長度,以實際的範例來舉例,購物車使用陣列儲存時,商品數將等於陣列長度。

操作方式

array.length

圖片範例

實際範例

const fruits = [1, 2, 3];

console.log(fruits.length);
// 輸出: 3

有趣的是,陣列的長度實際上是可以在被指派的,因此此處可以藉由指定長度的方式,新增額外的空格在陣列中

const fruits = [1, 2, 3];
fruits.length = 5;

console.log(fruits);
// 輸出:[1, 2, 3, 空白 × 2]

在陣列長度的控制中,我們甚至能故意縮小長度,來直接刪除後方的資料

const fruits = [1, 2, 3];
fruits.length = 2;

console.log(fruits);
// 輸出:[1, 2]

訪問陣列內容 [index]

在取得陣列內容中,我們可以藉由指定房間號碼(index)的形式來操作,並且同理,也可以藉由這個房間號碼來改變內部的值

操作方式

arrayName[index]

圖片範例

實際範例

const fruits = ['apple', 'banana', 'orange'];

console.log(fruits[0]);
// 輸出: apple
console.log(fruits[2]);
// 輸出: orange

反向藉由房間號碼進行修改操作

const fruits = ['apple', 'banana', 'orange'];

fruits[0] = 'bad apple';
console.log(fruits);
// 輸出:['bad apple', 'banana', 'orange']

新增或修改陣列中的內容 push、unshift、pop、shift

在陣列的操作中,我們很長需要使用新增的操作,以下會提供幾種主要的方式,對應不同的使用情況。

操作方式 - push

push 操作,可以幫我們在陣列的後方新增上內容,並且可以藉由 , 的分隔,來一次新增多筆的資料。

array.push(item1, item2, ..., itemX)

圖片範例

實際範例

const fruits = ['apple', 'banana', 'orange'];

fruits.push('bad apple', 'bad banana');
console.log(fruits);
// 輸出: ['apple', 'banana', 'orange', 'bad apple', 'bad banana']

操作方式 - unshift

unshift 的操作,會在陣列的前方幫我們新增所輸入的資料,也就是從 index 0 的位子開始。

array.unshift(item1, item2, ..., itemX)

圖片範例

實際範例

const fruits = ['apple', 'banana', 'orange'];

fruits.unshift('bad apple', 'bad banana');
console.log(fruits);
// 輸出: [ 'bad apple', 'bad banana', 'apple', 'banana', 'orange']

操作方式 - pop

pop 的操作,會進行以下行為

  • 刪除原本陣列中最後一個項目
  • 對原陣列進行異動
  • 回傳(return)剛剛刪除的最後一個項目
array.pop()

圖片範例

實際範例

const fruits = ['apple', 'banana', 'orange'];

const lastFruits = fruits.pop();

console.log(fruits);
// 輸出: ['apple', 'banana']
console.log(lastFruits);
// 輸出: orange <-剛剛刪除的最後一個項目

操作方式 - shift

shift 的操作,會進行以下行為

  • 刪除原本陣列中第一個項目
  • 對原陣列進行異動
  • 回傳(return)剛剛刪除的第一個項目
array.shift()

圖片範例

實際範例

const fruits = ['apple', 'banana', 'orange'];

const lastFruits = fruits.shift();

console.log(fruits);
// 輸出: ['banana', 'orange']
console.log(lastFruits);
// 輸出: apple <-剛剛刪除的最後一個項目

找尋內容在陣列中的 indexOf

其實在前端的開發中,我們比較少會使用到 indexOf 的操作,但在後端開發上,該筆資料在第幾筆出現或是否存在該筆資料,都是蠻常使用的參考依據。

操作方式

array.indexOf(item, start)

圖片範例

實際範例

const fruits = ['Banana', 'Orange', 'Apple', 'Mango'];

console.log(fruits.indexOf('Apple'));
// 輸出:2

console.log(fruits.indexOf('Appleefef'));
// 輸出:-1 <- 代表沒有找到

這裡還可以指令搜尋開始的位子

const fruits = ['Banana', 'Orange', 'Apple', 'Mango', 'Apple'];

console.log(fruits.indexOf('Apple', 3));
// 輸出:4

擷取陣列中的部分片段 splice

splice函式被用於在陣列指定範圍新增或刪除元素,並且回傳被刪除的元素

操作方式

array.splice(index, howmany, item1, ....., itemX)

陣列.splice(開始索引數,刪除元素數目,element1,element2)

圖片範例

實際範例

const fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];

console.log(fruits);
// 輸出:['Banana', 'Orange', 'Lemon', 'Apple', 'Mango']

console.log(fruits.splice(1, 3));
// 輸出:['Orange', 'Lemon' , 'Apple']

console.log(fruits);
// 輸出:['Banana', 'Mango']

在這裡也可以帶入其他元素,他將回從原先移除的 index 開始新增內容

const fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];

console.log(fruits.splice(1, 3, 'bad Orange', 'bad Lemon'));
// 輸出:['Orange', 'Lemon', 'Apple']

console.log(fruits);
// 輸出: ['Banana', 'bad Orange', 'bad Lemon', 'Mango']

取得陣列中的部分片段 slice

slice函式可取得陣列中指定範圍的元素陣列,語法中所輸入的索引值可以輸入複數,若為負數則由末端開始算起

操作方式

array.slice(start, end)

陣列.slice(開始索引值,結束索引值)

圖片範例

實際範例

const fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];

console.log(fruits.slice(1, 3));
// 輸出:['Orange', 'Lemon']

console.log(fruits);
// 輸出:['Banana', 'Orange', 'Lemon', 'Apple', 'Mango']

在 start 與 end 的設定中,也可以藉由給予負數的操作來使其從後方進行

const fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];

console.log(fruits.slice(-3, -2));
// 輸出:['Lemon']

console.log(fruits.slice(-2));
// 輸出:['Apple', 'Mango']

連結陣列測做 concat

concat函式被用於連結複數以上的陣列,並回傳連結後的結果

操作方式

array1.concat(array2, array3, ..., arrayX)

陣列.concat(陣列1,陣列2,陣列3,…)

實際範例

const fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
const badFruits = ['bad Orange', 'bad Lemon'];

console.log(fruits.concat(badFruits));
// 輸出: ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango', 'bad Orange', 'bad Lemon']

陣列排序操作 - sort、reverse

陣列的排序操作可以很粗略的排序陣列內容,並且還可以額外進行函式的操作

操作方式 - sort

array.sort(compareFunction)

陣列.sort(排序函式)

實際範例

const fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];

console.log(fruits.sort());
// 輸出: ['Apple', 'Banana', 'Lemon', 'Mango', 'Orange']

:::warning
注意:此處只能對英文字串進行排序
:::

操作方式 - reverse

array.reverse()

陣列.reverse()

實際範例

const fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];

console.log(fruits.reverse());
// 輸出: ['Mango', 'Apple', 'Lemon', 'Orange', 'Banana']

額外操作

陣列的操作都可以共同使用,如此處先排序再反轉的操作

const fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];

console.log(fruits.sort().reverse());
// 輸出: ['Orange', 'Mango', 'Lemon', 'Banana', 'Apple']

在陣列中的元素間插入輸入值

join函式會將陣列內的內容加上分隔區塊,然後以字串的形式進行回傳。

操作方式

array.join(separator)

陣列.join(分隔區塊)

實際範例

const fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];

console.log(fruits.join(' and '));
// 輸出: Banana and Orange and Lemon and Apple and Mango

上一篇
學習如何操作 DOM 與異步概念
下一篇
數組與對象更多內容頗析
系列文
給前端新手的圖文故事30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言